package com.fumin.service;

import com.fumin.beans.CacheKeyConstants;
import com.fumin.common.RequestHolder;
import com.fumin.dao.SysAclMapper;
import com.fumin.dao.SysRoleAclMapper;
import com.fumin.dao.SysRoleUserMapper;
import com.fumin.model.SysAcl;
import com.fumin.model.SysUser;
import com.fumin.util.JsonMapper;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**Sys 权限系统的核心处理实现类
 * @Author xiayuxuanmin
 * @Date 2019/11/13
 * @Description
 */
@Service
public class SysCoreService {
    @Resource
    private SysAclMapper sysAclMapper;
    @Resource
    private SysRoleUserMapper sysRoleUserMapper;
    @Resource
    private SysRoleAclMapper sysRoleAclMapper;
    @Resource
    private SysCacheService sysCacheService;

    /**
     * 获取当前用户的权限列表
     * @return
     */
    public List<SysAcl> getCurrentUserAclList(){
        int userId = RequestHolder.getCurrentUser().getId();
        return getUserAclList(userId);
    }

    /**
     * 获取一个角色已经分配拥有的权限点集合
     * @param roleId
     * @return
     */
    public List<SysAcl> getRoleAclList(int roleId){
        List<Integer> aclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(Lists.newArrayList(roleId));
        if (CollectionUtils.isEmpty(aclIdList)) {
            return Lists.newArrayList();
        }
        return sysAclMapper.getByIdList(aclIdList);
    }

    /**
     * 获取指定用户已经分配的权限点集合
     * @param userId
     * @return
     */
    public List<SysAcl> getUserAclList(int userId){
        if (isSupperAdmin()) {
            return sysAclMapper.getAll();
        }
        //获取用户已经分配拥有的角色ID集合
        List<Integer> userRoleIdList = sysRoleUserMapper.getRoleIdListByUserId(userId);
        if (CollectionUtils.isEmpty(userRoleIdList)) {
            //如果没有分配任何角色
            return Lists.newArrayList();
        }

        //根据角色ID集合查询角色分配拥有的权限ID集合
        List<Integer> userAclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(userRoleIdList);
        if (CollectionUtils.isEmpty(userAclIdList)) {
            return Lists.newArrayList();
        }
        return sysAclMapper.getByIdList(userAclIdList);
    }

    /**
     * 判断是否为超级管理员,因为初始分配权限的时候,只有超级管理员可以分配...
     * @return
     */
    public boolean isSupperAdmin(){
        SysUser sysUser = RequestHolder.getCurrentUser();
        //这里是定义一个假的超级管理员规则,实际中需要自定义
        if(sysUser.getMail().contains("admin")){
            return true;
        }
        return false;
    }

    /**
     * 判断用户是否有该url的访问权限
     * @param url
     * @return
     */
    public boolean hasUrlAcl(String url){
        if (isSupperAdmin()) {
            //超级管理员直接放行
            return true;
        }
        List<SysAcl> aclList = sysAclMapper.getByUrl(url);
        if (CollectionUtils.isEmpty(aclList)) {
            //该请求没有权限点限制,那么直接返回true
            return true;
        }
        //从缓冲中获取数据
//        List<SysAcl> userAclList = getCurrentUserAclListFormCache();
        List<SysAcl> userAclList = getCurrentUserAclList();
        Set<Integer> aclIdList = userAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());
        boolean hasValidAcl = false;//判断是否校验了权限(假如所有需要检测的权限点都无效,那么该值还是为false)
        //规则:只要有一个权限点符合条件(有权限),那么我们就认为有权限
        for (SysAcl sysAcl : aclList) {
            if (sysAcl == null || sysAcl.getStatus() != 1) {
                //权限点无效
                continue;
            }
            hasValidAcl = true;
            if (aclIdList.contains(sysAcl.getId())) {
                //只要有一个有权限,那么就直接return true
                return true;
            }
        }
        if (!hasValidAcl) {
            //如果没有检测有效的权限点,那么直接通行
            return true;
        }
        return false;
    }

    /**
     * 从缓存中获取数据,如果缓存中没有,则在缓冲中插入数据
     * @return
     */
    public List<SysAcl> getCurrentUserAclListFormCache(){
        int userId = RequestHolder.getCurrentUser().getId();
        String cacheValue = sysCacheService.getFromCache(CacheKeyConstants.USER_ACLS, String.valueOf(userId));
        if (StringUtils.isBlank(cacheValue)) {
            List<SysAcl> aclList = getCurrentUserAclList();
            //超时设置10分钟
            sysCacheService.saveCache(JsonMapper.obj2String(aclList),600,CacheKeyConstants.USER_ACLS, String.valueOf(userId));
            return aclList;
        }
        return JsonMapper.string2Obj(cacheValue, new TypeReference<List<SysAcl>>() {});
    }
}
